from datetime import datetime, timedelta, timezone
import io
import json
import os
import shutil
import subprocess
import tempfile
from celery import shared_task
from docxtpl import DocxTemplate, InlineImage
import fitz
from fitz import FileDataError
import qrcode
from docx.shared import Mm
import requests
from doc_service.models import RepModel, Report
from oss_service.views import bucket,digital_bucket
from reportservice.helpers import create_directories_if_not_exist
from yida_app_service.chengxiang_2025.xm_cloud_config import XmCloudClient
from yida_app_service.models import HzfwQrCode
from yida_app_service.utils.common_utils import merge_pdfs
from yida_app_service.chengxiang_2025.digital_sign_view import create_digital_sign_order_thread
import logging

from yida_app_service.utils.hzfw_utils import gen_qr_code
from .yida_config import YidaClient
from django.conf import settings
admin_user_id = "301546025724261514"
yida_client = YidaClient()
report_form_uuid = "FORM-5E859C69D49F452694E420EF7A162B4371MF"
logger = logging.getLogger(__name__)
tmp_path = os.path.join(settings.BASE_DIR, r'yida_app_service/chengxiang/resorce')
@shared_task
def generateReportPdf(uuid_string:str, form_data:dict, datasource:dict,report_code:str,report_type,form_inst_id):
    try:
        report_model = RepModel.objects.get(uuid=uuid_string)
    except RepModel.DoesNotExist:
        logger.error("未找到模板.")
    temp_dir = tempfile.mkdtemp()
    urlstr = form_data['attachmentField_lqrz4ehj']  # 获取上传的报告主体文件
    area = form_data.get("cascadeSelectField_lpgahbwq_id") # 地区
    report_content_info = json.loads(urlstr)[0]
    file_name = report_content_info["name"]
    ext = file_name.split(".")[-1]
    file_down:str = report_content_info["downloadUrl"]
    if file_down.startswith("https://api.zjxmyq.cn") or file_down.startswith("https://api.zjcxjc.cn"): # 已归档到oss
        file_down = file_down.replace("#","%23")
        response = requests.get(file_down)
    else:
        full_download_url = yida_client.get_full_download_url(
            user_id=admin_user_id, download_url=file_down)
        response = requests.get(full_download_url.body.result)
    if response.status_code == 200:
        file_content = response.content
        try:
            report = Report.objects.get(report_code=report_code)
        except Exception as err:
            report = Report(report_code=datasource["报告编号"],
                            model_id=report_model.id)
            report.report_path = rf"out-pdf/{datetime.now().strftime('%Y%m')}/{report.uuid}"
            report.save()
        # 获取报告页数
        tmp_report_path = rf"{temp_dir}/{report.report_path}"
        os.makedirs(tmp_report_path)# 创建报告缓存路径
        content_path = rf"{tmp_report_path}/content.{ext}"
        logger.info(f"pdf地址：{content_path}")
        with open(content_path, 'wb') as out:
            out.write(file_content)
        if ext == "docx":
            convert_to_pdf(content_path, tmp_report_path)
            content_path = rf"{tmp_report_path}/content.pdf"
        bucket.put_object_from_file(rf"{report.report_path}/content.pdf", content_path)
        try:
            with fitz.open(content_path) as doc_pdf:
                # 返回PDF的页数
                total_page = len(doc_pdf)
                datasource["全部页码"] = total_page + 1
            logger.info(f"报告内容上传成功")
        except FileDataError:
            logger.error("文件损坏或格式错误")
    tmp_file_path = rf"{tmp_path}/{report_model.path}"
    if not os.path.exists(tmp_file_path):
        create_directories_if_not_exist([tmp_file_path])
        logger.info(f"缓存模板不存在，从oss下载>>>>>>>")
        if bucket.object_exists(report_model.path):
            logger.info("文件已找到>>>>>>")
        bucket.get_object_to_file(report_model.path, tmp_file_path)
        logger.info(f"模板下载成功>>>>>>>")
    else:
        logger.info(f"本地模板文件已找到{tmp_file_path}")
    doc = DocxTemplate(tmp_file_path)
    extra_qr_data = datasource.get("hzfw")
    print(f"extra_qr_data>>>>>>{extra_qr_data}")
    if extra_qr_data:
        datasource["附加二维码"] = create_extra_qr_code(report_code)
    print(datasource)
    renderData = compile_tpl_data(doc, datasource)
    print(renderData)
    doc.render(renderData)
    tmpPdfpath = f"{temp_dir}/{report.report_path}"
    outdocpath = f"{tmpPdfpath}/cover.docx"
    doc.save(outdocpath)
    bucket.put_object_from_file(
        rf"{report.report_path}/cover.docx", outdocpath)
    convert_to_pdf(
        outdocpath, tmpPdfpath)
    # 合成pdf
    merge_pdfs([rf"{tmpPdfpath}/cover.pdf",
                rf"{tmpPdfpath}/content.pdf"], rf"{tmpPdfpath}/whole.pdf")
    logger.info(f"正在保存完整报告...")
    bucket.put_object_from_file(
        rf"{report.report_path}/whole.pdf", rf"{tmpPdfpath}/whole.pdf")
    report.completed_at = datetime.now()
    report.digital_sign_order_no = None
    report.save()
    shutil.rmtree(temp_dir)
    logger.info(f"报告已生成")
    form_instances = yida_client.get_form_items_by_ids(report_form_uuid, form_inst_id, yida_client.admin_user_id)
    if check_auto_create_sign_order(report_type,area):
        create_digital_sign_order_thread([form_inst_id],form_instances)


def check_auto_create_sign_order(report_type,area):
    '''校验是否需要自动发起签署'''
    if report_type in ["司法","造价","设计","纠纷","产品","衢州公司"]:
        return False
    if area:
        area_city = area[-1]
        if report_type == "鉴定" and area_city in ["ZJ_J_JJ",
                                            "ZJ_J_HY",
                                            "ZJ_J_LQ",
                                            "ZJ_J_LH",
                                            "ZJ_J_WL",
                                            "ZJ_J_YH",
                                            "ZJ_J_TT",
                                            "ZJ_J_XJ",
                                            "ZJ_J_SM",
                                            "ZJ_C_RA"]:
            return False
    return True

# 解析模板json
def compile_tpl_data(tpl: DocxTemplate, datasource: dict):
    renderData = {}
    for key, value in datasource.items():
        if isinstance(value, str):
            try:
                json_value = json.loads(value)
                tmp_value = compile_tpl_data(tpl, {key: json_value})
                renderData[key] = tmp_value[key]
            except:
                renderData[key] = value.replace('<', '&lt;').replace('>', '&gt;')
            continue
        if isinstance(value, list):
            clist = []
            for item in value:
                sub_opt = {
                    key: item
                }
                clist.append(compile_tpl_data(tpl, sub_opt))
                renderData[key] = clist
            continue
        if isinstance(value, (int, float)):
            renderData[key] = str(value)
        if isinstance(value, dict):
            if 'type' not in value:
                return compile_tpl_data(tpl, value)
            if value["type"] == "qrcode":
                url = genQrCode(value["text"])
                renderData[key] = InlineImage(tpl,
                                              image_descriptor=url, width=Mm(value["width"]))
            elif value["type"] == "img":
                renderData[key] = InlineImage(tpl,
                                              image_descriptor=value["url"], width=Mm(value["width"]))
            elif value["type"] == "date":
                timestamp = int(value["value"]) / 1000
                dt_object_utc = datetime.fromtimestamp(
                    timestamp, tz=timezone.utc)
                timezone_offset = 8  # Change this as per your local timezone
                local_timezone = timezone(timedelta(hours=timezone_offset))
                dt_object_local = dt_object_utc.astimezone(local_timezone)
                renderData[key] = dt_object_local.strftime(value["format"])
            continue
    return renderData



# 生成二维码图片


def genQrCode(qr_text):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(qr_text)  # 这里填写你想转换成二维码的文本
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    img_byte_arr = io.BytesIO()
    img.save(img_byte_arr, format='PNG')
    img_byte_arr.seek(0)
    return img_byte_arr



# 生成pdf

def convert_to_pdf(input_file_path, output_dir):
    print("正在生成pdf")
    # LibreOffice 命令行
    cmd = [
        "soffice",
        "--headless",
        "--convert-to",
        "pdf",
        "--outdir",
        output_dir,
        input_file_path
    ]
    subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return 


def create_extra_qr_code(report_code):
    xm_client = XmCloudClient()
    qr_code = HzfwQrCode.objects.filter(report_code=report_code, org_id=xm_client.hzfw_org_id, is_uploaded=False).order_by('-id').first()
    if not qr_code:
        try:
            res = gen_qr_code(xm_client.hzfw_org_id, report_code)
        except Exception as e:
            logger.error(f"生成二维码失败,{e}")
        if res["code"] == "ok":
            qr_data = res["qrcodestr"]
            qr_code = HzfwQrCode(report_code=report_code,
                                  org_id=xm_client.hzfw_org_id,
                                  company_name="chengxiang_2025",
                                  qr_code_content=qr_data)
            qr_code.save()
    qr_data = qr_code.qr_code_content
    return {
        "type": "qrcode",
        "text": qr_data,
        "width": 20
    }